// The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License");
// you may not use this file except in compliance with the License. You may obtain a copy of the License at
// http://www.mozilla.org/MPL/
// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
// ANY KIND, either express or implied. See the License for the specific terms governing rights and
// limitations under the License.
//
// This code was produced as part of the WaterBase project: http://www.waterbase.org
//
// Original author: Vimal Sharma, Chris George, 3/4/2008
//

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using System.Globalization;

namespace SWATGraph
{
	/// <summary>
	/// Description of MainForm.
	/// </summary>
	public partial class MainForm : Form
	{
		private string plotFile;
		
		public MainForm(string plotFileStr)
		{
			//
			// The InitializeComponent() call is required for Windows Forms designer support.
			//
			InitializeComponent();
			
			this.plotFile = plotFileStr;
		}
		
		short r;
		short c;
		string[,] x;
		double[,] y;
		string file_name;
		List<string> labels = new List<string>();

		private void cmbScaleX_Change()
		{
			set_scale();
		}

		private void cmbScaleX_Click()
		{
			set_scale();
		}

		private void cmbScaleY_Change()
		{
			set_scale();
		}

		private void cmbScaleY_Click()
		{
			set_scale();
		}

		private void Form1_Load(object sender, System.EventArgs e)
		{
			//MessageBox.Show("File to plot: " + plotFile);

			if ((plotFile != "") && System.IO.File.Exists(plotFile)) file_name = plotFile;
			else
			{
				System.Windows.Forms.DialogResult result = OpenFileMenu.ShowDialog();
				if (result == DialogResult.Cancel) Application.Exit();
				file_name = OpenFileMenu.FileName;
			}

			{ string db = resources.GetString("2dbar");
				chart_type.Items.Add(db);
				chart_type.Items.Add(resources.GetString("2dline"));
				//.Items.Add("2d XY") irrelevant for our purposes
				chart_type.SelectedIndex = 0;
			}

			{
				cmbScaleY.Items.Add(resources.GetString("log"));
				cmbScaleY.Items.Add(resources.GetString("percent"));
				cmbScaleY.Items.Add(resources.GetString("linear"));
				cmbScaleY.SelectedIndex = 2;
			}

			{
				cmbScaleX.Items.Add(resources.GetString("log"));
				cmbScaleX.Items.Add(resources.GetString("percent"));
				cmbScaleX.Items.Add(resources.GetString("linear"));
				cmbScaleX.SelectedIndex = 2;
			}

			{
				xvalues.Items.Add(resources.GetString("xcommon"));
				xvalues.Items.Add(resources.GetString("xindependent"));
				xvalues.SelectedIndex = 0;
			}
			file_read();
			

			flexigrid();
			draw_graph();
			write_stats();
			

		}
		public void flexigrid()
		{

			int intLoopCount;
			int i;
			int j;
			{
				MSFlexGrid1.Cols = c + 1;
				MSFlexGrid1.Rows = r + 1;

				for (intLoopCount = 1; intLoopCount <= (MSFlexGrid1.Rows - 1); intLoopCount++) {
					MSFlexGrid1.set_TextMatrix(intLoopCount, 0, intLoopCount.ToString());
				}
				for (intLoopCount = 1; intLoopCount <= (MSFlexGrid1.Cols - 1); intLoopCount++) {
					MSFlexGrid1.set_TextMatrix(0, intLoopCount, labels[intLoopCount - 1].ToString());
				}
				for (i = 1; i <= r; i++) {
					for (j = 1; j <= c; j++) {
						MSFlexGrid1.set_TextMatrix(i, j, x[i, j]);
					}
				}
			}
		}
		
		public void draw_graph()
		{
			// This gets called at the start before the array is written
			// and then crashes with c = 0, so guard against this
			if ((c > 0))
			{
				short i;
				short j;
				{
					MSChart1.Legend.Location.LocationType = MSChart20Lib.VtChLocationType.VtChLocationTypeBottom;
					MSChart1.RowCount = r;
					if (chart_type.Text == resources.GetString("2dline"))
					{
						MSChart1.chartType = MSChart20Lib.VtChChartType.VtChChartType2dLine;
						//.RowCount = r
						MSChart1.ColumnCount = (short) (c - 1);
						for (i = 1; i <= r; i++) {
							MSChart1.Row = i;
							for (j = 1; j <= c - 1; j++) {
								MSChart1.Column = j;
								MSChart1.ColumnLabel = labels[j];
								MSChart1.Data = x[i, j + 1];
							}
							MSChart1.RowLabel = x[i, 1];
						}
					}
					else
					{
						if (chart_type.Text == "2d XY")
						{
							// This does not seem to work, especially for labels
							MSChart1.chartType = MSChart20Lib.VtChChartType.VtChChartType2dXY;
							if (xvalues.Text == resources.GetString("xindependent"))
							{
								MSChart1.ColumnCount = c;
								for (i = 1; i <= r; i++) {
									MSChart1.Row = i;
									for (j = 1; j <= c; j++) {
										MSChart1.Column = j;
										//.ColumnLabel = labels.Item(j-1)
										MSChart1.Data = x[i, j];
									}
								}
							}
							else // xvalues.Text == resources.GetString("xcommon")
							{
								MSChart1.ColumnCount = (short) ((c - 2) * 2 + 3);
								for (i = 1; i <= r; i++) {
									MSChart1.Row = i;
									for (j = 1; j <= 2; j++) {
										MSChart1.Column = j;
										//.ColumnLabel = labels.Item(j)
										MSChart1.Data = x[i, j];
									}
								}
								for (i = 1; i <= r; i++) {
									MSChart1.Row = i;
									MSChart1.Column = 3;
									for (j = 3; j <= c; j++) {
										MSChart1.Data = x[i, 1];
										MSChart1.Column = (short) (MSChart1.Column + 1);
										MSChart1.Data = x[i, j];
										MSChart1.Column = (short) (MSChart1.Column + 1);
										//.ColumnLabel = labels.Item(j-1)
									}
								}
							}
						}
						else // chart_type.Text == resources.GetString("2dbar")
						{
							MSChart1.chartType = MSChart20Lib.VtChChartType.VtChChartType2dBar;
							//.RowCount = r
							MSChart1.ColumnCount = (short) (c - 1);
							
							for (i = 1; i <= r; i++) {
								MSChart1.Row = i;
								for (j = 1; j <= c - 1; j++) {
									MSChart1.Column = j;
									MSChart1.ColumnLabel = labels[j];
									MSChart1.Data = x[i, j + 1];

								}
								MSChart1.RowLabel = x[i, 1];
							}
						}
					}
					MSChart1.Plot.UniformAxis = false;

					MSChart1.Title.Text = Chart_title.Text;
					MSChart1.Plot.get_Axis(MSChart20Lib.VtChAxisId.VtChAxisIdY, null).AxisTitle.Text = Y_axis_title.Text;

					MSChart1.Plot.get_Axis(MSChart20Lib.VtChAxisId.VtChAxisIdX, null).AxisTitle.Text = x_axis_title.Text;
				}
				// set graph line width
				for (short k = 1; k <= MSChart1.Plot.SeriesCollection.Count(); k++)
				{
					MSChart1.Plot.SeriesCollection[k].Pen.Width = 25;
				}
			}
		}
		
		public void file_read()
		{
			// code assumes reading csv file with headings in first line,
			// and same number of fields in each line
			// also assumes decimal numbers use a period as number-decimal separator
			// (parsed as double using InvariantCulture)
			short i;
			short j;
			string line;
			char[] delims = new char[] {','}; // input is comma separated file
			string [] tokens;
			try
			{
				// first read to set number of rows and columns
				using (System.IO.StreamReader sr = new System.IO.StreamReader(file_name))
				{
					labels.Clear();
					line = sr.ReadLine();
					tokens = line.Split(delims);
					c = (short) tokens.Length;
					for (i = 0; i <= c - 1; i++)
					{
						labels.Add(tokens[i]);
					}
					int count = 0;
					bool finished = false;
					while (!finished)
					{
						line = sr.ReadLine();
						if (line == null)
						{
							finished = true;
							break;
						}
						tokens = line.Split(delims);
						if (tokens.Length != c)
						{
							finished = true;
							break;
						}
						count++;
					}
					r = (short) count;
				}
				// can now define dimensions of arrays to hold data.
				x = new string[r+1, c+1]; // strings for all data
				y = new double[r+1, c+1]; // doubles for numeric data
				using (System.IO.StreamReader sr = new System.IO.StreamReader(file_name))
				{
					sr.ReadLine(); // headings
					for (i = 1; i <= r; i++)
					{
						line = sr.ReadLine();
						tokens = line.Split(delims);
						for (j = 1; j <= c; j++)
						{
							x[i, j] = tokens[j-1];
							if (j == 1) y[i, j] = r; // skip dates, which are strings that are not doubles
							else y[i, j] = double.Parse(tokens[j-1], CultureInfo.InvariantCulture);
						}
					}
					x_axis_title.Text = labels[0];
				}
			}
			catch (Exception e)
			{
				MessageBox.Show(resources.GetString("cannotread") + file_name + ": " + e.Message, "SWATGraph",
				                MessageBoxButtons.OK, MessageBoxIcon.Error);
			}
		}

		public double sum(int series, int N)
		{
			double temp;
			int i;
			temp = 0;
			for (i = 1; i <= N; i++) {
				temp = temp + y[i, series];
			}
			return temp;
		}

		public double sq_sum(int series, int N)
		{
			double temp;
			int i;
			temp = 0;
			for (i = 1; i <= N; i++) {
				temp = temp + Math.Pow(y[i, series], 2);
			}
			return temp;


		}
		public double sumxy(int series1, int series2, int N)
		{
			double temp;
			int i;
			temp = 0;
			for (i = 1; i <= N; i++) {
				temp = temp + y[i, series1] * y[i, series2];

			}
			return temp;

		}


		public double r_sq(int series1, int series2, int N)
		{
			double functionReturnValue = 0;
			double sx;
			double sy;
			double sxy;
			sx = (sq_sum(series1, N) / N) - (Math.Pow(sum(series1, N), 2) / Math.Pow(N, 2));
			sy = (sq_sum(series2, N) / N) - (Math.Pow(sum(series2, N), 2) / Math.Pow(N, 2));
			sxy = (sumxy(series1, series2, N) / N) - (sum(series1, N) * sum(series2, N) / Math.Pow(N, 2));
			functionReturnValue = sxy / Math.Pow(((sx * sy)), 0.5);
			functionReturnValue = Math.Pow(functionReturnValue, 2);
			message_box.Text = message_box.Text + (char)13 + resources.GetString("series1") + 
				labels[series1-1] + resources.GetString("series2") + 
				labels[series2-1] + resources.GetString("correlationcoeff") + functionReturnValue.ToString("F3");
			return functionReturnValue;

		}

		public double nash(int series1, int series2, int N)
		{
			double functionReturnValue = 0;
			double mean;
			double num;
			double deno;
			short i;

			num = 0;
			deno = 0;
			mean = sum(series1, N) / N;

			for (i = 1; i <= N; i++) {
				num = num + Math.Pow((y[i, series1] - y[i, series2]), 2);
				deno = deno + Math.Pow((y[i, series1] - mean), 2);
			}

			functionReturnValue = 1 - (num / deno);
			message_box.Text = message_box.Text + (char)13 + resources.GetString("series1") +
				labels[series1-1] + resources.GetString("series2") + 
				labels[series2-1] + resources.GetString("nash") + functionReturnValue.ToString("F3");
			return functionReturnValue;

		}

		private void exp_excel_Click(object sender, System.EventArgs e)
		{

		}

		/// <summary>
		/// Cannot get this to work.
		/// Always crashes on any reference to Clipboard after EditCopy.
		/// Use copyToClipboard instead.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void saveBMP_Click(object sender, System.EventArgs e)
		{

			string strsavefile;
			//Bitmap image1;
			{
				// CommonDialog object
				SaveFileMenu.Filter = "Pictures (*.bmp)|*.bmp";
				SaveFileMenu.DefaultExt = "bmp";
				SaveFileMenu.ShowDialog();
				strsavefile = SaveFileMenu.FileName;
				if (strsavefile == "") return;
				
			}
			//Dim rect As System.Drawing.Rectangle = New System.Drawing.Rectangle(MSChart1.Location, MSChart1.Size)
			//image1 = new System.Drawing.Bitmap(MSChart1.Size.Width, MSChart1.Size.Height)
			//chartPanel.DrawToBitmap(image1,rect)

			//IDataObject oChartClipboard;
			//MessageBox.Show("1");
			Clipboard.Clear();
			// copy image of chart
			//MessageBox.Show("2");
			MSChart1.EditCopy();
			//MessageBox.Show("3");
			Application.DoEvents();
			try
			{
				MessageBox.Show("1");
				IDataObject iData = Clipboard.GetDataObject();
				MessageBox.Show("2");
				if (Clipboard.ContainsImage()) MessageBox.Show("Clipboard has image");
			}
			catch (Exception ex)
			{
				MessageBox.Show(ex.Message);
			}
			//else MessageBox.Show("Clipboard has no image");
			//image1 = (Bitmap) Clipboard.GetDataObject().GetData("Bitmap", true);
			//if (image1 == null) MessageBox.Show("Image is null");
			//else
			//{
			//MessageBox.Show("5");
			//image1.Save(strsavefile, System.Drawing.Imaging.ImageFormat.Bmp);
			//MessageBox.Show("6");
			//}
			
			//For i As Integer = 1 To 100000
			//	Application.DoEvents()
			//Next i
			//if (ClipBoard.ContainsData(System.Windows.Forms.DataFormats.Serializable))
			//{
			//	MessageBox.Show("Has data");
			//}
			//else
			//{
			//	MessageBox.Show("No data");
			//}
			//oChartClipboard = Clipboard.GetDataObject();
			//image1 = oChartClipboard.GetData(System.Windows.Forms.DataFormats.Bitmap, true);
			//image1.Save(strsavefile, System.Drawing.Imaging.ImageFormat.Bmp);
			//MessageBox.Show("3");
			//MSChart1.EditCopy()
			// image1 = Clipboard.GetData(DataFormats.Bitmap)
			//        image1 = My.Computer.Clipboard.GetData("System.Drawing.Bitmap")
			// image1.Save(strsavefile, System.Drawing.Imaging.ImageFormat.Bmp)
			//SavePicture(Clipboard.GetData, strsavefile)it Sub
		}

		public void set_scale()
		{
			if (cmbScaleY.Text == resources.GetString("log"))
				MSChart1.Plot.get_Axis(MSChart20Lib.VtChAxisId.VtChAxisIdY, null).AxisScale.type = MSChart20Lib.VtChScaleType.VtChScaleTypeLogarithmic;
			else
			{
				if (cmbScaleY.Text == resources.GetString("percent"))
				{
					MSChart1.Plot.get_Axis(MSChart20Lib.VtChAxisId.VtChAxisIdY, null).AxisScale.type = MSChart20Lib.VtChScaleType.VtChScaleTypePercent;
					MSChart1.Plot.get_Axis(MSChart20Lib.VtChAxisId.VtChAxisIdY, null).AxisScale.PercentBasis = MSChart20Lib.VtChPercentAxisBasis.VtChPercentAxisBasisMaxChart;
				}
				else // cmbScaleY.Text == resources.GetString("linear")
					MSChart1.Plot.get_Axis(MSChart20Lib.VtChAxisId.VtChAxisIdY, null).AxisScale.type = MSChart20Lib.VtChScaleType.VtChScaleTypeLinear;
			}
			if (cmbScaleX.Text == resources.GetString("log"))
				MSChart1.Plot.get_Axis(MSChart20Lib.VtChAxisId.VtChAxisIdX, null).AxisScale.type = MSChart20Lib.VtChScaleType.VtChScaleTypeLogarithmic;
			else
			{
				if (cmbScaleX.Text == resources.GetString("percent"))
				{
					MSChart1.Plot.get_Axis(MSChart20Lib.VtChAxisId.VtChAxisIdX, null).AxisScale.type = MSChart20Lib.VtChScaleType.VtChScaleTypePercent;

					MSChart1.Plot.get_Axis(MSChart20Lib.VtChAxisId.VtChAxisIdX, null).AxisScale.PercentBasis = MSChart20Lib.VtChPercentAxisBasis.VtChPercentAxisBasisMaxChart;
				}
				else // (cmbScaleX.Text == resources.GetString("linear"))
					MSChart1.Plot.get_Axis(MSChart20Lib.VtChAxisId.VtChAxisIdX, null).AxisScale.type = MSChart20Lib.VtChScaleType.VtChScaleTypeLinear;
			}

		}


		private void graph_Click(object sender, System.EventArgs e)
		{
			draw_graph();
		}

		private void cmbScaleY_SelectedIndexChanged(object sender, System.EventArgs e)
		{
			set_scale();
		}

		private void cmbScaleX_SelectedIndexChanged(object sender, System.EventArgs e)
		{
			set_scale();
		}



		private void chart_type_SelectedIndexChanged(object sender, System.EventArgs e)
		{
			if (chart_type.Text == "2d XY")
			{
				xvalues.Visible = true;
				xAxisSeries.Visible = true;
			}
			else
			{
				xAxisSeries.Visible = false;
				xvalues.Visible = false;
			}
			draw_graph();
		}

		private void new_file_Click(object sender, System.EventArgs e)
		{
			System.Windows.Forms.DialogResult result = OpenFileMenu.ShowDialog();
			if (result == DialogResult.Cancel) return;
			file_name = OpenFileMenu.FileName;
			file_read();
			flexigrid();
			draw_graph();
			write_stats();
		}

		
		void copyToClipboard(object sender, EventArgs e)
		{
			MSChart1.EditCopy();
			Application.DoEvents();
			MessageBox.Show(resources.GetString("chartclip"));
		}
		
		void close_clock(object sender, EventArgs e)
		{
			this.Close();
		}

		void write_stats()
		{
			message_box.Text = "";
			
			double r_square;
			double nash_value;
			int i;
			int j;
			for (i = 2; i <= c; i++) {
				for (j = i + 1; j <= c; j++) {
					r_square = r_sq(i, j, r);
				}
			}

			for (i = 2; i <= c; i++) {
				for (j = i + 1; j <= c; j++) {
					// only compute Nash-Sutcliffe Efficiency
					// if one plot is observed,
					// and use that as the first plot
					if (labels[i-1].StartsWith("observed"))
						if (!labels[j-1].StartsWith("observed"))
							nash_value = nash(i, j, r);
						else nash_value = 0; // just to avoid ambiguous else
					else if (labels[j-1].StartsWith("observed"))
						nash_value = nash(j, i, r);
				}
			}

		}
	}
}


